import fnmatch
import yaml

class PermError(Exception):
    pass

class other:
    def find(self, list, permname):
        return fnmatch.filter(list, permname)

    def listinlist(self, list_a, list_b):
        return not False in set(list(a in list_b for a in list_a))

    def list_removefromlist(self, needremove, list_a):
        for i in needremove:
            if i in set(list_a):
                del list_a[list_a.index(i)]
            else:
                return False

        return self.listinlist(needremove, list_a) == False

    def dict2list(self, dict):
        list_a = list()
        for i in dict.keys():
            list_a.append((i, dict[i]))

        return list_a

class Permission(other):
    def __init__(self, FileName='Nothing.'):
        if FileName != 'Nothing.':
            self.ReadFile(FileName)
        self.Object = dict()

        self.support = {}
        # For Parent
        self.Parent_TempList = list()

        # Support for Pickle
        try:
            self.support['pickle'] = __import__('pickle')
            def PickleDump(self, FileName):
                with open(FileName, 'wb') as f:
                    self.support['pickle'].dump(self.Object, f)

            def PickleLoad(self, FileName):
                with open(FileName, 'rb') as f:
                    self.Object = self.support['pickle'].load(f)

            self.PickleLoad = PickleLoad
            self.PickleDump = PickleDump
        except:
            self.support['pickle'] = False

        # Support for Json
        try:
            self.support['json'] = __import__('json')
            def JsonDump(self, FileName):
                with open(FileName, 'w') as f:
                    f.write(self.support['json'].dumps(self.Object))

            def JsonLoad(self, FileName):
                with open(FileName, 'r') as f:
                    self.Object = self.support['json'].loads(f.read())

            self.JsonDump = JsonDump
            self.JsonLoad = JsonLoad
        except:
            self.support['json'] = False

        # Support for shelve:
        try:
            self.support['shelve'] = __import__('shelve')
            def ShelveLoad(self, FileName):
                with self.support['shelve'].open(FileName) as f:
                    self.Object = dict(f)

            def ShelveDump(self, FileName):
                with self.support['shelve'].open(FileName) as f:
                    for i in self.Object.keys():
                        f[i] = self.Object[i]

            self.ShelveDump = ShelveDump
            self.ShelveLoad = ShelveLoad
        except:
            self.support['shelve'] = False

    def __enter__(self):
        return self

    def __exit__(self, type, value, trace):
        self.DumpFile(self.FileName)

    def FileInstaller(self):
        # Permission
        self.Object['Permission'] = dict()
        self.Object['Permission']['Node'] = list()
        self.Object['Permission']['Disable'] = list()
        # Group
        self.Object['Group'] = dict()
        self.Object['Group']['SuperNode'] = list()
        self.Object['Group']['PermissionSet'] = dict()
        self.Object['Group']['ParentSet'] = dict()
        # User
        self.Object['User'] = dict()
        self.Object['User']['PermissionSet'] = dict()
        self.Object['User']['ParentSet'] = dict()
        self.Object['User']['BlackList'] = dict()
        self.Object['User']['BlackList']['Enable'] = True
        self.Object['User']['BlackList']['RedPlayerList'] = list() # SAO
        # Bind
        self.Object['BindHub'] = dict()
        # Info
        self.Object['Info'] = dict()
        self.Object['Info']['Group'] = dict()
        self.Object['Info']['User'] = dict()

    def ReadFile(self, FileName):
        with open(FileName, "rt", encoding='utf-8') as this:
            self.Object = yaml.load(this.read())
        self.FileName = FileName

    def DumpFile(self, FileName):
        with open(FileName, "w", encoding='utf-8') as this:
            yaml.dump(self.Object, this)

    def Return(self):
        return self.Object 

    def NodeList(self):
        return self.Object['Permission']['Node']

    def AddNode(self, NodeName):
        if NodeName in self.NodeList():
            return True
        self.Object['Permission']['Node'].append(NodeName)
        return NodeName in self.Object['Permission']['Node']

    def DelNode(self, NodeName):
        if NodeName in self.NodeList():
            self.Object['Permission']['Node'].pop(self.Object['Permission']['Node'].index(NodeName))
            return NodeName not in self.Object['Permission']['Node']
        else:
            raise PermError('Node NOT in the node list.')

    def GroupList(self):
        return self.Object['Group']['SuperNode']

    def AddGroup(self, NodeName):
        if NodeName in self.GroupList():
            return True

        self.Object['Group']['SuperNode'].append(NodeName)
        self.Object['Info']['Group'][NodeName] = dict()

        return NodeName in self.Object['Group']['SuperNode']

    def DelGroup(self, SuperNodeName):
        if SuperNodeName == "":
            return False
        try:
            index = self.GroupList().index(SuperNodeName)
        except ValueError:
            raise PermError('SuperNodeName not in PermObject.')

        self.Object['Group']['SuperNode'].pop(index) # Del SuperNode

        if SuperNodeName in self.Object["Group"]["ParentSet"].keys():
            del self.Object["Group"]["ParentSet"][SuperNodeName]
            # Del Parent
        
        for i in self.Object['User']['ParentSet'].keys():
            if self.Object['User']['ParentSet'][i] == SuperNodeName:
                del self.Object['User']['ParentSet'][i]
        if SuperNodeName not in self.GroupList():
            return True
        return SuperNodeName not in self.GroupList()

    def GroupWithUserBind(self):
        return self.Object['User']['ParentSet']

    def IsInGroup(self, GroupName, UserName):
        if UserName in set(self.GroupWithUserBind().keys()):
            if GroupName == self.Object['User']['ParentSet'][UserName]:
                return True
            else:
                return False

        return False

    def WhatGroup(self, UserName):
        if UserName in set(self.GroupWithUserBind().keys()):
            return self.GroupWithUserBind()[UserName]
        else:
            return 'default'

    def DoHaveTheGroup(self, GroupNode):
        if GroupNode in set(self.GroupList()):
            return True
        else:
            return False

    def UserObject(self):
        return self.Object['User']['PermissionSet']

    def TheUserObject(self, User):
        return self.UserObject()[User]

    def AddUser(self, User):
        self.Object['User']['PermissionSet'][User] = list()
        #self.Object['Info']['User'][User] = list()

    def DoUserHavePerm(self, PermNode, UserName):
        if UserName not in self.UserObject():
            return False

        if PermNode in self.UserObject()[UserName]:
            return True

        return False

    def GivePermToUser(self, PermNode, User):
        if User not in self.UserObject():
            self.AddUser(User)

        if not False in set(list(a in self.UserObject()[User] for a in self.find(self.NodeList(), PermNode))):
            return True

        if False in set(list(a in set(self.NodeList()) for a in self.find(self.NodeList(), PermNode))):
            return False
        
        nodelist = list(self.find(self.NodeList(), PermNode))
        self.Object['User']['PermissionSet'][User] += nodelist
        self.Object['User']['PermissionSet'][User] = list(set(list(self.Object['User']['PermissionSet'][User])))
        return self.listinlist(self.find(self.NodeList(), PermNode), self.Object['User']['PermissionSet'][User])

    def DeprivePermByUser(self, PermNode, User):
        if User in self.UserObject():
            return self.list_removefromlist(self.find(self.TheUserObject(User), PermNode), self.Object['User']['PermissionSet'][User])
        else:
            return False

    def GroupParent(self, Group=''):
        if Group == '':
            return self.Object['Group']['ParentSet']
        else:
            if Group in self.GroupList():
                if Group not in self.Object['Group']['ParentSet']:
                    self.Object['Group']['ParentSet'][Group] = list()

                return self.Object['Group']['ParentSet'][Group]
            else:
                return False

    def AddParent(self, Group, ParentGroup):
        if ParentGroup == Group:
            return False

        if ParentGroup is not list():
            if ParentGroup in self.GroupList():
                if ParentGroup in self.GroupParent(Group):
                    return True

                self.Object['Group']['ParentSet'][Group] += ParentGroup
                return ParentGroup in self.Object['Group']['ParentSet'][Group]
            else:
                return False
        else:
            if self.listinlist(self.GroupList(), ParentGroup):
                if self.listinlist(self.GroupParent(Group), ParentGroup):
                    return True

                self.Object['Group']['ParentSet'][Group] += ParentGroup
                return self.listinlist(ParentGroup, self.Object['Group']['ParentSet'])
            else:
                return False

        return False


    def DepriveParent(self, Group, DepriveParent):
        if DepriveParent == Group:
            return False

        if DepriveParent is not list():
            if DepriveParent in self.GroupList():
                if DepriveParent in self.GroupParent(Group):
                    return True

                index = self.Object['Group']['ParentSet'][Group].index(DepriveParent)
                del self.Object['Group']['ParentSet'][Group][index]
                return DepriveParent not in self.Object['Group']['ParentSet'][Group]
            else:
                return False
        else:
            if self.listinlist(self.GroupList(), DepriveParent):
                if self.listinlist(self.GroupParent(Group), DepriveParent):
                    return True

                self.list_removefromlist(DepriveParent, self.Object['Group']['ParentSet'][Group])
                return self.listinlist(DepriveParent, self.Object['Group']['ParentSet'][Group]) == False
            else:
                return False

        return False

    def EraseParent(self, Group):
        if self.GroupParent(Group) != False:
            self.Object['Group']['ParentSet'][Group] = list()
            return True
        else:
            return False
        
        return False

    def GroupPermSetObject(self):
        return self.Object['Group']['PermissionSet']

    def GetTheGroupPerm(self, Group):
        if Group not in self.GroupList():
            return False

        if Group not in self.GroupPermSetObject():
            return list()
        
        return self.GroupPermSetObject()[Group]

    def TheGroupPermSetObject(self, Group):
        if Group not in self.GroupList():
            return False

        return self.GroupPermSetObject()[Group]

    def GivePermToGroup(self, Group, Permission):
        if Group not in self.GroupList():
            return False

        if not Group in self.GroupPermSetObject():
            self.Object['Group']['PermissionSet'][Group] = list()

        finder = self.find(self.NodeList(), Permission)

        if self.listinlist(finder, self.TheGroupPermSetObject(Group)):
            return True
        
        if self.listinlist(finder, self.NodeList()) == False:
            return False

        self.Object['Group']['PermissionSet'][Group] += list(finder)
        self.Object['Group']['PermissionSet'][Group] = list(set(list(self.Object['Group']['PermissionSet'][Group])))
        return self.listinlist(finder, self.Object['Group']['PermissionSet'][Group])

    def DeprivePermByGroup(self, PermNode, Group):
        if Group in self.GroupPermSetObject():
            return self.list_removefromlist(self.find(self.TheGroupPermSetObject(Group), PermNode), self.Object['Group']['PermissionSet'][Group])
        else:
            return False

    def __CreateSelfParentObject(self, Group):
        #print("Group: " + Group)
        if self.GroupParent() is not None:
            if Group in self.GroupParent():
                if isinstance(self.GroupParent(Group), list):
                    self.Parent_TempList += self.GroupParent(Group)
                    for i in range(len(self.GroupParent(Group))):
                        ITrue = True
                        key = list(self.GroupParent(Group))[i]

                        if key not in self.GroupParent():
                            ITrue = False

                        if ITrue != False:
                            value = self.GroupParent()[key]
                            if key in self.GroupList():
                                self.Parent_TempList += value
                            for i in value:
                                if key == i:
                                    raise PermError("The Child of an object should not have its own.")
                                self.__CreateSelfParentObject(i)

    def GetAllParent(self, Group):
        self.Parent_TempList = list()
        try:
            self.__CreateSelfParentObject(Group)
        except PermError:
            return False

        Ireturn = list(set(list(self.Parent_TempList)))
        Ireturn.sort()
        return Ireturn

    def GetGroupPerm(self, Group):
        IReturn = list()
        for a in self.GetAllParent(Group):
            IReturn += self.GetTheGroupPerm(a)

        if self.GetTheGroupPerm(Group) != False:
            IReturn += self.GetTheGroupPerm(Group)
        return IReturn

    def DoGroupHavePerm(self, PermNode, Group):
        if Group not in self.GroupPermSetObject():
            return False

        if PermNode in self.GetGroupPerm(Group):
            return True

        return False

    def UserGroupObject(self):
        return self.Object['User']['ParentSet']

    def TheUserGroupObject(self, User):
        if User not in self.UserGroupObject():
            self.Object['User']['ParentSet'][User] = 'default'

        return self.Object['User']['ParentSet'][User]

    def MoveUserParent(self, User, Group):
        if User not in self.UserGroupObject():
            self.Object['User']['ParentSet'][User] = 'default'

        if Group not in self.GroupList():
            return False

        if Group == self.TheUserGroupObject(User):
            return True

        self.Object['User']['ParentSet'][User] = Group
        return self.Object['User']['ParentSet'][User]

    def DeleteUserParent(self, User):
        if User not in self.UserGroupObject():
            return False

        self.Object['User']['ParentSet'][User] = 'default'
        return self.Object['User']['ParentSet'][User] == 'default'

    def ReMove(self, User, NewGroup):
        if User not in self.UserGroupObject():
            return False

        self.Object['User']['ParentSet'][User] = NewGroup
        return self.Object['User']['ParentSet'][User] == NewGroup

    # 自此,所有旧版功能迁移完毕,开始写特色

    def CheckObject(self):
        # 不要乱搞文件,除非你想死一死,我不介意加个self.FileInstaller(),然后你就会丢掉所有的数据.
        # 该函数有点问题,建议多运行几次.

        # 用户权限
        for user in self.Object['User']['PermissionSet'].keys():
            # 校验是否有没有注册的权限被加到用户权限内.
            for i in self.Object['User']['PermissionSet'][user]:
                if i not in self.NodeList():
                    index = self.Object['User']['PermissionSet'][user].index(i)
                    del self.Object['User']['PermissionSet'][user][index]

            self.Object['User']['PermissionSet'][user] = list(set(list(self.Object['User']['PermissionSet'][user])))

        # 用户父组
        for user in self.Object['User']['ParentSet'].keys():
            # 校验用户的父组是否没有注册
            if self.Object['User']['ParentSet'][user] not in self.GroupList():
                self.DeleteUserParent(user)

        # 组权限
        for group in self.Object['Group']['PermissionSet'].keys():
            # 校验被设定权限的组是否没有注册
            if group not in self.GroupList():
                del self.Object['Group']['PermissionSet'][group]

            # 校验是否有没有注册的权限被加到权限组权限内.
            for i in self.Object['Group']['PermissionSet'][group]:
                if i not in self.NodeList():
                    index = self.Object['Group']['PermissionSet'][group].index(i)
                    del self.Object['Group']['PermissionSet'][group][index]

            self.Object['Group']['PermissionSet'][group] = list(set(list(self.Object['Group']['PermissionSet'][group])))

        # 组继承
        for group in self.Object['Group']['ParentSet'].keys():
            # 校验被设定继承组的组是否被注册
            if group not in self.GroupList():
                del self.Object['Group']['ParentSet'][group]

            # 校验被设置为其他组的继承组的组是否被注册
            if not self.listinlist(self.Object['Group']['ParentSet'][group], self.NodeList()):
                for i in self.Object['Group']['ParentSet'][group]:
                    if i not in self.GroupList():
                        index = self.Object['Group']['ParentSet'][group].index(i)
                        del self.Object['Group']['ParentSet'][group][index]


        # 修复重复的权限和组节点
        self.Object['Permission']['Node'] = list(set(list(self.Object['Permission']['Node'])))
        self.Object['Group']['SuperNode'] = list(set(list(self.Object['Group']['SuperNode'])))
        self.Object['User']['BlackList']['RedPlayerList'] = list(set(list(self.Object['User']['BlackList']['RedPlayerList'])))
        
    def DisablePerm(self, Perm):
        if Perm not in self.NodeList():
            return False

        del self.Object['Permission']['Node'][self.Object['Permission']['Node'].index(Perm)]
        self.Object['Permission']['Disable'] += Perm
        return Perm in self.Object['Permission']['Disable'] and Perm not in self.Object['Permission']['Node']

    def EnablePerm(self, Perm):
        # 破镜重圆?
        if Perm not in self.Object['Permission']['Disable'] or Perm in self.NodeList():
            return False

        del self.Object['Permission']['Disable'][self.Object['Permission']['Disable'].index(Perm)]
        self.AddNode(Perm)
        return Perm not in self.Object['Permission']['Disable'] or Perm in self.NodeList()

    def BlackList(self):
        if self.Object['User']['BlackList']['Enable'] != True:
            raise PermError('BlackList is not enable.')

        return self.Object['User']['BlackList']["RedPlayerList"]

    def EnableBL(self):
        self.Object['User']['BlackList']['Enable'] = True
        return self.Object['User']['BlackList']['Enable']

    def DisableBL(self):
        self.Object['User']['BlackList']['Enable'] = False
        return self.Object['User']['BlackList']['Enable'] == False

    def AppendBlackList(self, User):
        BL = self.BlackList()
        if User in BL:
            return False
        BL = self.BlackList()
        self.Object['User']['BlackList']["RedPlayerList"].append(User)
        return User in BL

    def MoveOutBlackList(self, User):
        BL = self.BlackList()
        if User not in BL:
            return False
        BL = self.BlackList()
        del self.Object['User']['BlackList']["RedPlayerList"][self.Object['User']['BlackList']["RedPlayerList"].index(User)]
        return User not in BL

    def IsInBlackList(self, User):
        return User in self.Object['User']['BlackList']["RedPlayerList"]

    # Bind
    def BindObject(self):
        return self.Object['BindHub']

    def GetBind(self, Key):
        if Key not in self.BindObject():
            return False
        
        return self.Object['BindHub'][Key]

    def CreateBind(self, Key, Value):
        if Key in self.BindObject() and Value == self.GetBind(Key):
            return True

        self.Object['BindHub'][Key] = Value
        return self.Object['BindHub'][Key] == Value

    def DeleteBind(self, Key):
        if Key not in self.BindObject():
            return False

        del self.Object['BindHub'][Key]
        return Key not in self.Object['BindHub']

    def ReBind(self, Key, NewValue):
        if Key not in self.BindObject():
            return False

        self.Object['BindHub'][Key] = NewValue
        return self.Object['BindHub'][Key] == NewValue

    def DoHavePerm(self, Perm, User):
        return self.DoUserHavePerm(Perm, User) or self.DoGroupHavePerm(Perm, self.WhatGroup(User))

    # 丢人的Info

    def Info(self):
        return self.Object['Info']

    def InfoUser(self):
        return self.Info()['User']

    def InfoGroup(self):
        return self.Info()['Group']

    def InfoGroupDict(self, Group):
        if Group not in self.Object['Info']['Group'].keys() and Group in self.GroupList():
            self.Object['Info']['Group'][Group] = dict()

        return self.Object['Info']['Group'][Group]

    def InfoUserDict(self, User):
        if User not in self.Object['Info']['User'].keys():
            self.Object['Info']['User'][User] = dict()

        return self.Object['Info']['User'][User]
    
    def GetGroupInfo(self, Group, Key):
        return self.InfoGroup()[Group][Key]

    def GroupNewInfo(self, Group, Key, Value):
        if Group not in self.Object['Info']['Group'].keys() and Group in self.GroupList():
            self.Object['Info']['Group'][Group] = dict()
        else:
            return False

        self.Object['Info']['Group'][Group][Key] = Value
        return True

    def GetUserInfo(self, User, Key):
        return self.InfoUser()[User][Key]

    def UserNewInfo(self, User, Key, Value):
        if User not in self.Object['Info']['User'].keys():
            self.Object['Info']['User'][User] = dict()

        self.Object['Info']['User'][User][Key] = Value
        return True
    # 不要用.
